﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Media.Effects;

namespace GraphosControls
{
    /// <summary>
    /// Arguments used when transition animation completes
    /// </summary>
    public class TransitionAnimationCompleteEventArgs : EventArgs
    {
        public TransitionAnimationCompleteEventArgs(IEnumerable<UIElement> elems)
        {
            RemovedElements = elems;
        }

        /// <summary>
        /// Gets the UIElements which were animated and need dealing with
        /// </summary>
        public IEnumerable<UIElement> RemovedElements { get; private set; }
    }

    /// <summary>
    /// Used for dealing with intermediate animations of nodes, edges and labels
    /// </summary>
    public class TransitionUtility
    {
        public TransitionUtility()
        {
            m_animCompleteTimer = new DispatcherTimer();
            m_animCompleteTimer.Tick += TransitionAnimationsComplete_Tick;
            m_animCompleteTimer.Interval = TimeSpan.FromSeconds(1.5);
        }

        #region Apply Animation public methods

        public void ApplyDestroyNodeAnimation(UIElement elem)
        {
            m_elementsBeingAnimated.Add(elem);
            m_animCompleteTimer.Start();

            DoubleAnimation opacity = new DoubleAnimation();
            opacity.To = 0.0;
            opacity.AccelerationRatio = 0.25;
            opacity.DecelerationRatio = 0.75;
            opacity.Duration = Const.DestroyNodeTime;
            opacity.Freeze();
            elem.BeginAnimation(UIElement.OpacityProperty, opacity);
        }
        public void ApplyDestroyEdgeAnimation(UIElement elem)
        {
            m_elementsBeingAnimated.Add(elem);
            m_animCompleteTimer.Start();

            DoubleAnimation opacity = new DoubleAnimation();
            opacity.To = 0.0;
            opacity.AccelerationRatio = 0.25;
            opacity.DecelerationRatio = 0.75;
            opacity.Duration = Const.DestroyEdgeTime;
            opacity.Freeze();
            elem.BeginAnimation(UIElement.OpacityProperty, opacity);
        }
        public void ApplyDestroyLabelAnimation(TextBlock textblock)
        {
            m_elementsBeingAnimated.Add(textblock);
            m_animCompleteTimer.Start();

            double opacityFrom = textblock.Opacity;
            double opacityTo = 0.0;
            ApplyOpacityAnimation(textblock, opacityFrom, opacityTo, Const.DestroyLabelTime.TotalSeconds);
        }

        public static void ApplyCreateNodeAnimation(UIElement elem)
        {
            DoubleAnimation opacity = new DoubleAnimation();
            opacity.To = 1.0;
            opacity.Duration = Const.CreateNodeTime;
            opacity.AccelerationRatio = 0.75;
            opacity.DecelerationRatio = 0.25;
            opacity.BeginTime = TimeSpan.FromSeconds(0.0);
            opacity.Freeze();
            elem.BeginAnimation(UIElement.OpacityProperty, opacity);

        }
        public static void ApplyCreateEdgeAnimation(VisualEdge edge)
        {
            //double opacityFrom = edge.Opacity;
            //double opacityTo = 1.0;
            DoubleAnimation opacity = new DoubleAnimation();
            opacity.To = 1.0;
            opacity.BeginTime = TimeSpan.FromSeconds(0.25);
            opacity.AccelerationRatio = 0.75;
            opacity.DecelerationRatio = 0.25;
            opacity.Duration = Const.CreateEdgeTime;
            opacity.Freeze();
            edge.BeginAnimation(UIElement.OpacityProperty, opacity);
            //return opacity;
            //ApplyOpacityAnimation(edge, opacityFrom, opacityTo, Const.CreateEdgeTime.TotalSeconds);
        }
        public static void ApplyCreateLabelAnimation(TextBlock textblock)
        {
            double opacityFrom = 0.0;
            double opacityTo = 1.0;
            ApplyOpacityAnimation(textblock, opacityFrom, opacityTo, Const.CreateEdgeTime.TotalSeconds);
        }

        public static void ApplyPrimaryEdgeHighlightAnimation(VisualEdge edge)
        {
            DoubleAnimation x = new DoubleAnimation();
            DoubleAnimation y = new DoubleAnimation();
            x.From = 0;
            x.To = 10;
            y.From = 0.0;
            y.To = 0.35;
            x.Duration = TimeSpan.FromSeconds(0.5);
            y.Duration = TimeSpan.FromSeconds(0.5);
            x.Freeze();
            y.Freeze();

            OuterGlowBitmapEffect effect = new OuterGlowBitmapEffect();
            effect.GlowColor = (edge.DesiredStrokeBrush as SolidColorBrush).Color;
            effect.BeginAnimation(OuterGlowBitmapEffect.GlowSizeProperty, x);
            effect.BeginAnimation(OuterGlowBitmapEffect.OpacityProperty, y);

            edge.LabelTextBlock.BitmapEffect = effect;
        }
        public static void ApplyEdgeHighlightAnimation(VisualEdge edge)
        {
            double labelOpacityFrom = edge.LabelTextBlock.Opacity;
            double labelOpacityTo = 1.0;
            ApplyOpacityAnimation(edge.LabelTextBlock, labelOpacityFrom, labelOpacityTo, 0.5);

            DoubleAnimation x = new DoubleAnimation();
            DoubleAnimation y = new DoubleAnimation();
            x.From = 0;
            x.To = 10;
            y.From = 0.0;
            y.To = 0.35;
            x.Duration = TimeSpan.FromSeconds(0.5);
            y.Duration = TimeSpan.FromSeconds(0.5);
            x.Freeze();
            y.Freeze();

            OuterGlowBitmapEffect effect = new OuterGlowBitmapEffect();
            effect.GlowColor = (edge.DesiredStrokeBrush as SolidColorBrush).Color;
            effect.BeginAnimation(OuterGlowBitmapEffect.GlowSizeProperty, x);
            effect.BeginAnimation(OuterGlowBitmapEffect.OpacityProperty, y);

            edge.LabelTextBlock.BitmapEffect = effect;

           

           

        }
        public static void ApplyGlowAnimation(UIElement elem, Color color)
        {
            DoubleAnimation x = new DoubleAnimation();
            DoubleAnimation y = new DoubleAnimation();
            x.From = 0;
            x.To = 10;
            y.From = 0.0;
            y.To = 0.35;
            x.Duration = TimeSpan.FromSeconds(0.5);
            y.Duration = TimeSpan.FromSeconds(0.5);
            x.Freeze();
            y.Freeze();

            OuterGlowBitmapEffect effect = new OuterGlowBitmapEffect();
            effect.GlowColor = color;
            effect.BeginAnimation(OuterGlowBitmapEffect.GlowSizeProperty, x);
            effect.BeginAnimation(OuterGlowBitmapEffect.OpacityProperty, y);

            elem.BitmapEffect = effect;
        }
        public static void ApplyUnGlowAnimation(UIElement elem)
        {
            elem.BitmapEffect = null;
        }
        public static void ApplyLabelFadeInAnimation(UIElement elem)
        {
            DoubleAnimation opacity = new DoubleAnimation();
            opacity.To = 1.0;
            opacity.Duration = TimeSpan.FromSeconds(0.75);
            opacity.Freeze();
            elem.BeginAnimation(UIElement.OpacityProperty, opacity);
        }
        public static void ApplyLabelFadeOutAnimation(UIElement elem)
        {
            DoubleAnimation opacity = new DoubleAnimation();
            opacity.To = 0.0;
            opacity.Duration = TimeSpan.FromSeconds(0.75);
            opacity.Freeze();
            elem.BeginAnimation(UIElement.OpacityProperty, opacity);
        }
        public static void ApplyEdgeResetAnimation(VisualEdge edge)
        {
            double labelOpacityFrom = edge.LabelTextBlock.Opacity;
            double labelOpacityTo = 0.0;
            if (labelOpacityFrom != labelOpacityTo)
            {
                DoubleAnimation opacity = new DoubleAnimation();
                //opacity.From = from;
                opacity.To = labelOpacityTo;
                opacity.Duration = TimeSpan.FromSeconds(0.75);
                opacity.Freeze();
                edge.LabelTextBlock.BeginAnimation(UIElement.OpacityProperty, opacity);
            }

            edge.LabelTextBlock.BitmapEffect = null;


            
        }

        

        private static DoubleAnimation ApplyOpacityAnimation(UIElement elem, double from, double to, double seconds)
        {
            if (from != to)
            {
                DoubleAnimation opacity = new DoubleAnimation();
                //opacity.From = from;
                opacity.To = to;
                opacity.Duration = TimeSpan.FromSeconds(seconds);
                opacity.Freeze();
                elem.BeginAnimation(UIElement.OpacityProperty, opacity);
                return opacity;
            }
            return null;
        }
        private static DoubleAnimation ApplyStrokeThicknessAnimation(Shape shape, double from, double to, double seconds)
        {
            if (from != to)
            {
                DoubleAnimation thick = new DoubleAnimation();
                //thick.From = from;
                thick.To = to;
                thick.Duration = TimeSpan.FromSeconds(seconds);
                thick.Freeze();
                shape.BeginAnimation(Shape.StrokeThicknessProperty, thick);
                return thick;
            }
            return null;
        }
        private static ColorAnimation ApplyBrushAnimation(SolidColorBrush brush, SolidColorBrush to, double seconds)
        {
            ColorAnimation result = null;
            //if (from.Color != to.Color)
            {
                ColorAnimation color = new ColorAnimation();
                color.To = to.Color;
                color.Duration = TimeSpan.FromSeconds(seconds);
                color.Freeze();
                brush.BeginAnimation(SolidColorBrush.ColorProperty, color);
                result = color;
            }
            //if (from.Opacity != to.Opacity)
            {
                DoubleAnimation opacity = new DoubleAnimation();
                //opacity.From = from.Opacity;
                opacity.To = to.Opacity;
                opacity.Duration = TimeSpan.FromSeconds(seconds);
                opacity.Freeze();
                brush.BeginAnimation(SolidColorBrush.OpacityProperty, opacity);
            }
            return result;
        }
        private static DoubleAnimation ApplyScaleAnimation(UIElement elem, double fromX, double toX, double fromY, double toY, double seconds)
        {
            DoubleAnimation scale = new DoubleAnimation();
            ScaleTransform trans = new ScaleTransform();
            scale.Duration = TimeSpan.FromSeconds(seconds);
            if (fromX != toX)
            {
                scale.From = fromX;
                scale.To = toX;
                trans.BeginAnimation(ScaleTransform.ScaleXProperty, scale);

            }
            if (fromY != toY)
            {
                scale.From = fromX;
                scale.To = toX;
                trans.BeginAnimation(ScaleTransform.ScaleYProperty, scale);
            }
            if (trans.HasAnimatedProperties)
                elem.RenderTransform = trans;

            return scale;
        }

        #endregion

        #region Events

        public delegate void AnimationCompleteEventHandler(object sender, TransitionAnimationCompleteEventArgs e);
        public event AnimationCompleteEventHandler TransitionAnimationComplete;
        private void OnTransitionAnimationComplete(IList<UIElement> elems)
        {
            if (TransitionAnimationComplete != null && elems.Count > 0)
            {
                TransitionAnimationComplete(this, new TransitionAnimationCompleteEventArgs(elems));
            }
            m_elementsBeingAnimated = new List<UIElement>();
        } 

        #endregion

        #region Event Handlers

        private void TransitionAnimationsComplete_Tick(object sender, EventArgs e)
        {
            DispatcherTimer timer = sender as DispatcherTimer;
            timer.Stop();

            OnTransitionAnimationComplete(m_elementsBeingAnimated);
        } 

        #endregion

        #region Fields

        private DispatcherTimer m_animCompleteTimer;
        private List<UIElement> m_elementsBeingAnimated = new List<UIElement>(); 

        #endregion

        #region Constants

        private static class Const
        {
            public static TimeSpan CreateNodeTime = TimeSpan.FromSeconds(1.5);
            public static TimeSpan CreateEdgeTime = TimeSpan.FromSeconds(1.75);
            public static TimeSpan CreateLabelTime = TimeSpan.FromSeconds(1.5);
            public static TimeSpan DestroyNodeTime = TimeSpan.FromSeconds(0.5);
            public static TimeSpan DestroyEdgeTime = TimeSpan.FromSeconds(0.5);
            public static TimeSpan DestroyLabelTime = TimeSpan.FromSeconds(0.5);
        } 

        #endregion
    }
    
}
